package qc.module.qms.algorithm.NumericCalc.method;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import qc.common.core.enums.qms.QmsPointTimeSegmentEnum;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.common.core.utils.QmsTimeUtil;
import qc.module.qms.algorithm.NumericCalc.dto.*;
import qc.module.qms.algorithm.dto.QmsPointDto;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * QmsCalcMethodBase 计算方法基类
 *
 * @author QuCheng Tech
 * @since 2025/9/8
 */
public class QmsNumericCalcMethodBase implements IQmsNumericCalcMethod {
    private static final Logger logger = LoggerFactory.getLogger(QmsNumericCalcMethodBase.class);

    /**
     * 计算的目标对象信息
     */
    public QmsNumericCalcDest dest;
    /**
     * 计算使用的方法
     */
    public QmsNumericCalcUseMethod method;
    /**
     * 计算的输入，参数、时序数据、工作曲线
     */
    public QmsNumericCalcInput input;
    /**
     * 计算的结果，是否成功、结果数据集合
     */
    public QmsNumericCalcResult result;
    /**
     * 计算目标中的点号所属站点编码，在构造方法中自动获取并赋值，方便后继使用
     */
    protected String destPointStcd = null;

    /**
     * 计算方法基类构造函数，需同时传入计算目标、计算方法和输入；构造函数中先对计算目标和计算方法进行有效性验证（计算输入的验证需要再各计算方法子类中根据自身需求进行验证）
     *
     * @param dest   计算目标
     * @param method 计算方法
     * @param input  计算输入，包含输入参数、输入时序数据序列和工作曲线
     * @return
     * @author QuCheng Tech
     * @since 2025/9/13
     */
    public QmsNumericCalcMethodBase(QmsNumericCalcDest dest, QmsNumericCalcUseMethod method, QmsNumericCalcInput input) {
        logger.debug("QmsNumericCalcMethodBase");

        this.dest = dest;
        this.method = method;
        this.input = input;

        //先初始化计算结果成功标记为true表示成功
        boolean validSuccess = true;//验证是否成功，先默认为成功
        StringBuilder sbValidMsg = new StringBuilder();//验证失败时的提示信息

        //验证计算目标是否合理
        if (this.dest == null) {
            validSuccess = false;
            sbValidMsg.append("计算目标对象不能为空，");
        } else {
            //判断计算目标中的点号：点号对象不能为空、点号ID不能为空、
            if (this.dest.getPoint() == null) {
                validSuccess = false;
                sbValidMsg.append("计算目标中点号对象不能为空，");
            } else {
                QmsPointDto point = this.dest.getPoint();
                if (StringUtils.isBlank(point.getPointid())) {
                    validSuccess = false;
                    sbValidMsg.append("计算目标中点号ID不能为空，");
                }
            }
            //判断计算目标中的时段类型，不能为未定义
            if (this.dest.getTmseg() == QmsPointTimeSegmentEnum.UN_DEFINE) {
                validSuccess = false;
                sbValidMsg.append("计算目标中时段类型不能为[" + this.dest.getTmseg().getName() + "]，");
            }
            //判断计算目标中的起止时间，不能为空，先后顺序正确
            if (this.dest.getBeginTime() == null) {
                validSuccess = false;
                sbValidMsg.append("计算目标中起始时间不能为空，");
            }
            if (this.dest.getEndTime() == null) {
                validSuccess = false;
                sbValidMsg.append("计算目标中截止时间不能为空，");
            }
            if (this.dest.getBeginTime() != null && this.dest.getEndTime() != null) {
                if (this.dest.getBeginTime().isAfter(this.dest.getEndTime())) {
                    validSuccess = false;
                    sbValidMsg.append("计算目标中起始时间不能大于截止时间，");
                }
            }
        }
        //验证计算方法是否合理
        if (this.method == null) {
            validSuccess = false;
            sbValidMsg.append("计算方法对象不能为空，");
        } else {
            //判断计算方法中的方法编码不能为空、方法内容不能为空（为空时无法根据内容进行分别调用）
            if (StringUtils.isBlank(this.method.getMethodcode())) {
                validSuccess = false;
                sbValidMsg.append("计算方法编码不能为空，");
            }
            if (StringUtils.isBlank(this.method.getContent())) {
                validSuccess = false;
                sbValidMsg.append("计算方法体内容不能为空，");
            }
            //计算方法中其他属性不需要验证；输入参数和时序数据无法确定数量和是否必须要有配置
        }

        //如果不合理设置计算结果成功标记为失败，如果验证通过对计算结果的目标时间序列进行初始化
        //验证计算目标和计算方法是否合理，不合理时设置返回结果中的成功标记和提示信息，合理时进行计算结果数据的初始化时间段
        this.result = new QmsNumericCalcResult();
        this.result.setSuccess(validSuccess);
        if (validSuccess == false) {
            //验证计算目标和方法错误
            this.result.setMsg(sbValidMsg.toString());
            logger.error("QmsNumericCalcMethodBase 初始化中验证计算目标和计算方法失败，" + sbValidMsg.toString());
        } else {
            //验证通过
            //根据计算目标中的点号对象信息进行内部变量赋值
            this.destPointStcd = this.dest.getPoint().getStcd();
            QmsPointTimeSegmentEnum tmseg = this.dest.getTmseg();
            logger.debug("QmsNumericCalcMethodBase 初始化中验证计算目标和计算方法通过，本次计算目标点号[" + this.dest.getPoint().getPointid()
                    + "]，时段类型[" + tmseg.toString() + "]，点号站点编码[" + this.destPointStcd + "]，计算目标时间段["
                    + LocalDateTimeUtil.formatDateTime(this.dest.getBeginTime()) + "]-[" + LocalDateTimeUtil.formatDateTime(this.dest.getEndTime()) + "]");
            //时段类型为实时或分钟时无法根据指定的起止时间得到要计算的每个时间点，此时不进行结果数据集合的初始化
            if (tmseg.getIndex() >= QmsPointTimeSegmentEnum.HOUR.getIndex()) {
                Map<LocalDateTime, Double> initResultDatas = new LinkedHashMap<>();
                //小时及以上时段类型才能根据时段长度计算出时间点
                LocalDateTime beginTime = this.dest.getBeginTime();
                LocalDateTime endTime = this.dest.getEndTime();
                //对计算目标传入的起止时间再取一个时段初时间，避免外部传入时间错误导致计算返回的数据时间点延续错误的问题
                LocalDateTime periodBeginTime = QmsTimeUtil.getPeriodTime(beginTime, tmseg);
                LocalDateTime periodEndTime = QmsTimeUtil.getPeriodTime(endTime, tmseg);
                LocalDateTime time = periodBeginTime;
                while (time.isAfter(periodEndTime) == false) {
                    logger.debug("QmsNumericCalcMethodBase 初始化计算结果数据集合，时间[" + LocalDateTimeUtil.formatDateTime(time) + "]");
                    //初始化每个时间点的数据值为null
                    initResultDatas.put(time, null);

                    time = QmsTimeUtil.getNextPeriodTime(time, tmseg);
                }

                //计算出的应有时段数
                int dueResultCount = initResultDatas.size();
                logger.debug("QmsNumericCalcMethodBase 初始化中验证计算目标和计算方法通过，本次计算目标点号[" + this.dest.getPoint().getPointid()
                        + "]，时段类型[" + tmseg.toString() + "]，初始化计算结果应有数据[" + dueResultCount + "]条，结果数据时间段["
                        + LocalDateTimeUtil.formatDateTime(periodBeginTime) + "]-[" + LocalDateTimeUtil.formatDateTime(periodEndTime) + "]");

                this.result.setDueCount(dueResultCount);
                this.result.setDatas(initResultDatas);
                //测试初始化的计算结果数据集合顺序
                for (Map.Entry<LocalDateTime, Double> entry : this.result.getDatas().entrySet()) {
                    logger.debug("QmsNumericCalcMethodBase 初始化计算结果数据集合，时间[" + LocalDateTimeUtil.formatDateTime(entry.getKey()) + "]");
                }
            }
        }
    }

    /**
     * 调试输出计算目标信息
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void debugOutputDest() {
        logger.debug("计算目标对象--dest--输出开始");
        if (this.dest == null) {
            logger.debug("计算目标对象--dest--对象为null");
        } else {
            logger.debug("计算目标对象--dest--点号：" + this.dest.getPoint().getPointid());
            logger.debug("计算目标对象--dest--点号时段类型：" + this.dest.getTmseg().getName());
            logger.debug("计算目标对象--dest--起始时间：" + LocalDateTimeUtil.formatDateTime(this.dest.getBeginTime()));
            logger.debug("计算目标对象--dest--截止时间：" + LocalDateTimeUtil.formatDateTime(this.dest.getEndTime()));
        }
        logger.debug("计算目标对象--dest--输出结束");
    }

    /**
     * 调试输出计算方法信息
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void debugOutputMethod() {
        logger.debug("计算方法对象--method--输出开始");
        if (this.method == null) {
            logger.debug("计算方法对象--method--对象为null");
        } else {
            logger.debug("计算方法对象--method--编码：" + this.method.getMethodcode());
            logger.debug("计算方法对象--method--名称：" + this.method.getMethodname());
            logger.debug("计算方法对象--method--输入序列数量：" + this.method.getIntscount());
            logger.debug("计算方法对象--method--方法体：" + this.method.getContent());
            logger.debug("计算方法对象--method--结果数值单位换算系数：" + this.method.getValuemodulus());
            logger.debug("计算方法对象--method--结果数值乘以时间长度类型：" + this.method.getValuetmtype());
            if (this.method.getParams() != null && this.method.getParams().size() > 0x0) {
                logger.debug("计算方法对象--method--输入参数：共" + method.getParams().size() + "个");
                logger.debug("编码\t名称\t值类型\t非空\t默认值\t为输入点号参数\t描述");
                for (QmsNumericCalcUseMethodParam param : this.method.getParams()) {
                    logger.debug(param.getParamcode() + "\t" + param.getParamname() + "\t" + param.getValuedatatype().getName() + "\t" + param.getNotnull() + "\t" + param.getDefaultvalue() + "\t" + param.getIsinput() + "\t" + param.getDescription());
                }
            } else {
                logger.debug("输入参数：无");
            }
            if (this.method.getIntsdatas() != null && this.method.getIntsdatas().size() > 0x0) {
                logger.debug("计算方法对象--method--输入时序数据：共" + this.method.getIntsdatas().size() + "个");
                //logger.debug("编码\t名称\t值类型\t非空\t默认值\t为输入点号参数\t描述");
                for (QmsNumericCalcUseMethodInputTsDatas inputTsDatas : this.method.getIntsdatas()) {
                    //logger.debug(param.getParamcode() + "\t" + param.getParamname() + "\t" + param.getValuedatatype().getName() + "\t" + param.getNotnull() + "\t" + param.getDefaultvalue() + "\t" + param.getIsinput() + "\t" + param.getDescription());
                }
            } else {
                logger.debug("计算方法对象--method--输入时序数据：无");
            }
        }
        logger.debug("计算方法对象--method--输出结束");
    }

    /**
     * 调试输出计算输入，包含输入参数、时序数据和工作曲线
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void debugOutputInput() {
        debugOutputInputParams();
        debugOutputInputTimeSerialDatas();
        debugOutputInputWorkLines();
    }

    /**
     * 调试输出计算输入参数
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void debugOutputInputParams() {
        logger.debug("计算输入参数--input.params--输出开始");
        if (this.input == null) {
            logger.debug("计算输入参数--input--对象为null");
        } else {
            if (this.input.getParams() == null || this.input.getParams().size() < 0x1) {
                logger.debug("计算输入参数--input.params--计算输入参数集合为空");
            } else {
                logger.debug("计算输入参数--input.params--计算输入参数：共" + this.input.getParams().size() + "个站点参数");
                logger.debug("站点编码\t参数个数");
                for (QmsNumericCalcInputStationParams stationParams : input.getParams()) {
                    if (stationParams.getItems() != null && stationParams.getItems().size() > 0x0) {
                        logger.debug("计算输入参数：站点编码[" + stationParams.getStcd() + "]，参数个数[" + stationParams.getItems().size() + "]");
                        for (QmsNumericCalcInputParamItem paramItem : stationParams.getItems()) {
                            QmsNumericCalcUseMethodParam param = paramItem.getParam();
                            List<QmsNumericCalcInputParamValue> values = paramItem.getValues();

                            logger.debug("计算输入参数：站点编码[" + stationParams.getStcd() + "]，参数编码[" + param.getParamcode() + "]，参数名称[" + param.getParamname()
                                    + "]，参数值数据类型[" + param.getValuedatatype().getName() + "]，是否非空[" + param.getNotnull() + "]，默认值[" + param.getDefaultvalue()
                                    + "]，是否为输入数据站点参数[" + param.getIsinput() + "]，参数描述[" + param.getDescription() + "]");
                            if (values != null && values.size() > 0x0) {
                                logger.debug("计算输入参数：站点编码[" + stationParams.getStcd() + "]，参数编码[" + param.getParamcode() + "]，共有参数值[" + values.size() + "]个");
                                for (QmsNumericCalcInputParamValue pv : values) {
                                    logger.debug("计算输入参数：站点编码[" + stationParams.getStcd() + "]，参数编码[" + param.getParamcode() + "]，参数值[" + pv.getParamvalue()
                                            + "]，写入时间[" + LocalDateTimeUtil.formatDateTime(pv.getIntm()) + "]，更新时间[" + LocalDateTimeUtil.formatDateTime(pv.getUptm())
                                            + "]，起始有效时间[" + LocalDateTimeUtil.formatDateTime(pv.getBegintm()) + "]，截止有效时间[" + LocalDateTimeUtil.formatDateTime(pv.getEndtm())
                                            + "]，每年起始有效时间[" + LocalDateTimeUtil.formatDateTime(pv.getRepeatbegintm()) + "]，每年截止有效时间[" + LocalDateTimeUtil.formatDateTime(pv.getRepeatendtm())
                                            + "]，参数值ID[" + pv.getId() + "]");
                                }
                            } else {
                                logger.debug("计算输入参数：站点编码[" + stationParams.getStcd() + "]，参数编码[" + param.getParamcode() + "]，共有参数值[0]个");
                            }
                        }
                    } else {
                        logger.debug("计算输入参数：站点编码[" + stationParams.getStcd() + "]，参数个数[0]");
                    }
                }
            }
        }
        logger.debug("计算输入参数--input.params--输出结束");
    }

    /**
     * 调试输出计算输入时序数据
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void debugOutputInputTimeSerialDatas() {
        logger.debug("计算输入时间序列数据--input.timeSerialDatas--输出开始");
        if (this.input == null) {
            logger.debug("计算输入时间序列数据--input--计算输入对象为null");
        } else {
            if (this.input.getTimeSerialDatas() == null || this.input.getTimeSerialDatas().size() < 0x1) {
                logger.debug("计算输入时间序列数据--input.timeSerialDatas--计算输入时间序列数据集合为空");
            } else {
                logger.debug("计算输入时间序列数据--input.timeSerialDatas--计算输入时间序列数据：共" + this.input.getTimeSerialDatas().size() + "个");
                logger.debug("数据序列名称\t点号\t站点编码\t时段类型\t数据数量");
                for (QmsNumericCalcInputTimeSerialDatas inputTimeSerialDatas : this.input.getTimeSerialDatas()) {
                    if (inputTimeSerialDatas.datas != null && inputTimeSerialDatas.datas.size() > 0x0) {
                        logger.debug(inputTimeSerialDatas.getSerialName() + "\t" + inputTimeSerialDatas.getPointid() + "\t" + inputTimeSerialDatas.getStcd() + "\t" + inputTimeSerialDatas.getTmseg().getName() + "\t" + inputTimeSerialDatas.getDatas().size());
                        for (Map.Entry<LocalDateTime, Double> entry : inputTimeSerialDatas.datas.entrySet()) {
                            logger.debug(LocalDateTimeUtil.formatDateTime(entry.getKey()) + "\t" + entry.getValue());
                        }
                    } else {
                        logger.debug(inputTimeSerialDatas.getSerialName() + "\t" + inputTimeSerialDatas.getPointid() + "\t" + inputTimeSerialDatas.getStcd() + "\t" + inputTimeSerialDatas.getTmseg().getName() + "\t 0");
                    }
                }
            }
        }
        logger.debug("计算输入时间序列数据--input.timeSerialDatas--输出结束");
    }

    /**
     * 调试输出计算输入工作曲线
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void debugOutputInputWorkLines() {
        logger.debug("计算输入工作曲线--input.workLines--输出开始");
        if (this.input == null) {
            logger.debug("计算输入工作曲线--input--计算输入对象为null");
        } else {
            if (this.input.getWorkLines() == null || this.input.getWorkLines().size() < 0x1) {
                logger.debug("计算输入工作曲线--input.workLines--计算输入工作曲线集合为空");
            } else {
                logger.debug("计算输入工作曲线--input.workLines--计算输入工作曲线：共" + this.input.getWorkLines().size() + "个");
                //logger.debug("编码\t名称\t值类型\t非空\t默认值\t为输入点号参数\t描述");
                //for (QmsNumericCalcInputStationParams param : input.getWorkLines()) {
                //    logger.debug(param.getParamcode() + "\t" + param.getParamname() + "\t" + param.getValuedatatype().getName() + "\t" + param.getNotnull() + "\t" + param.getDefaultvalue() + "\t" + param.getIsinput() + "\t" + param.getDescription());
                //}
            }
        }
        logger.debug("计算输入工作曲线--input.workLines--输出结束");
    }

    /**
     * 调试输出计算结果
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void debugOutputResult() {
        logger.debug("计算结果对象--result--输出开始");
        logger.debug("计算结果对象--result--是否计算成功：" + result.isSuccess());
        logger.debug("计算结果对象--result--提示信息：" + result.getMsg());
        logger.debug("计算结果对象--result--应有数量：" + result.getDueCount());
        logger.debug("计算结果对象--result--实有数量：" + result.getActualCount());
        if (result.getDatas() != null && result.getDatas().size() > 0x0) {
            logger.debug("计算结果对象--result--计算结果集合数量：共" + result.getDatas().size() + "个");
            logger.debug("时间\t数值");
            for (Map.Entry<LocalDateTime, Double> entry : result.getDatas().entrySet()) {
                logger.debug(LocalDateTimeUtil.formatDateTime(entry.getKey()) + "\t" + entry.getValue());
            }
        } else {
            logger.debug("计算结果对象--result--计算结果集合数量：无");
        }
        if (result.getFails() != null && result.getFails().size() > 0x0) {
            logger.debug("计算结果对象--result--未能成功计算出数据值的时段数量：共" + result.getDatas().size() + "个");
            logger.debug("时间\t提示信息");
            for (Map.Entry<LocalDateTime, String> entry : result.getFails().entrySet()) {
                logger.debug(LocalDateTimeUtil.formatDateTime(entry.getKey()) + "\t" + entry.getValue());
            }
        } else {
            logger.debug("计算结果对象--result--未能成功计算出数据值的时段数量：无");
        }
        logger.debug("计算结果对象--result--输出结束");
    }

    /**
     * 获取指定参数编码的参数配置和参数值集合
     *
     * @param stcd      站点编码
     * @param paramCode 参数编码
     * @return qc.module.qms.algorithm.NumericCalc.dto.QmsNumericCalcInputParamItem
     * @author QuCheng Tech
     * @since 2025/9/27
     */
    public QmsNumericCalcInputParamItem getInputParamItem(String stcd, String paramCode) {
        //站点编码和参数编码为空时无法获取参数值
        if (StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(paramCode)) {
            if (this.input != null && this.input.getParams() != null && this.input.getParams().size() > 0x0) {
                //先根据站点编码筛选
                Optional<QmsNumericCalcInputStationParams> filterByStcdParams = this.input.getParams().stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), stcd)).findFirst();
                if (filterByStcdParams != null && filterByStcdParams.isPresent()) {
                    List<QmsNumericCalcInputParamItem> stationParams = filterByStcdParams.get().getItems();
                    if (stationParams != null && stationParams.size() > 0x0) {
                        //根据参数编码筛选
                        Optional<QmsNumericCalcInputParamItem> filterByParamCodeParam = stationParams.stream().filter(p -> p.getParam() != null && StringUtils.equalsIgnoreCase(p.getParam().getParamcode(), paramCode)).findFirst();
                        if (filterByParamCodeParam != null && filterByParamCodeParam.isPresent()) {
                            return filterByParamCodeParam.get();
                        }
                    }
                }
            }
        }

        return null;
    }

    /**
     * 设置计算方法结果，包含计算结果应有数量、实有数量和结果数据序列
     *
     * @param dueResultCount    应有数据数量
     * @param actualResultCount 实有数据数量
     * @param datas             结果数据序列
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/17
     */
    public void setResult(int dueResultCount, int actualResultCount, Map<LocalDateTime, Double> datas) {
        if (this.result != null) {
            //先清空结果中的已有数据
            this.result.setDueCount(0x0);
            this.result.setActualCount(0x0);
            this.result.setDatas(null);

            if (dueResultCount >= 0x0)
                this.result.setDueCount(dueResultCount);
            if (actualResultCount >= 0x0)
                this.result.setActualCount(actualResultCount);
            if (datas != null && datas.size() > 0x0)
                this.result.setDatas(datas);
        }
    }

    /**
     * 计算结果数值单位换算
     *
     * @return void
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public void calcResultValueUnitConvert() {
        logger.debug("calcResultValueUnitConvert");
        //如果本来没有计算结果不进行单位换算处理
        if (this.method != null && this.dest != null && this.result != null && this.result.getDatas() != null && this.result.getDatas().size() > 0x0) {
            //如果计算方法中的单位换算系数没有设置、乘以时间长度类型也没有设置，两者均未设置时也不需要进行单位换算
            double modulus = Double.NaN;
            String tmtypeStr = null;
            //单位换算系数不能为空或NaN，系数可以是0或负值
            if (this.method.getValuemodulus() != null && this.method.getValuemodulus().isNaN() == false)
                modulus = this.method.getValuemodulus().doubleValue();
            //位换算乘以时间长度的设置必须时在计算的目标点号时段长度≥设置的乘以时间长度
            QmsPointTimeSegmentEnum tmseg = this.dest.getTmseg();
            //点号时段类型为未定义、实时、分钟的无法确定点号的时段长度，因此不做乘以时间长度的处理
            if (tmseg.getIndex() > QmsPointTimeSegmentEnum.MINUTE.getIndex() && StringUtils.isNotBlank(this.method.getValuetmtype())) {
                String str = this.method.getValuetmtype();
                //判断单位换算乘以时间长度的设置是否正确，不正确的当做未设置；只能设置为d、h、m、s表示乘以天数、小时数、分钟数、秒数
                if (tmseg.getIndex() > QmsPointTimeSegmentEnum.DAY.getIndex() && StringUtils.equalsIgnoreCase(str, "d"))//设置为日的点号时段类型应大于日
                    tmtypeStr = "d";
                else if (tmseg.getIndex() > QmsPointTimeSegmentEnum.HOUR.getIndex() && StringUtils.equalsIgnoreCase(str, "h"))//设置为小时的点号时段类型应大于小时
                    tmtypeStr = "h";
                else if (StringUtils.equalsIgnoreCase(str, "m"))//设置为分组的点号时段类型应大于分钟
                    tmtypeStr = "m";
                else if (StringUtils.equalsIgnoreCase(str, "s"))//设置为秒的点号时段类型应大于秒
                    tmtypeStr = "s";
            }

            logger.info("calcResultValueUnitConvert 计算结果数值单位换算，计算结果点号[" + this.dest.getPoint().getPointid() + "]，时段类型[" + tmseg.toString()
                    + "]，单位换算系数[" + modulus + "]，单位换算时间长度字符串[" + tmtypeStr + "]");

            if (Double.isNaN(modulus) == false || StringUtils.isNotBlank(tmtypeStr)) {
                Map<LocalDateTime, Double> beforeDatas = this.result.getDatas();
                //遍历每个时间点的数据进行处理，如果时间点的数值原来为null或NaN保持原数值
                Map<LocalDateTime, Double> afterDatas = new LinkedHashMap<>();
                for (Map.Entry<LocalDateTime, Double> entry : beforeDatas.entrySet()) {
                    if (entry.getValue() == null) {
                        //原来的时间点值为null或NaN
                        logger.info("calcResultValueUnitConvert 计算结果数值单位换算，数据时间[" + LocalDateTimeUtil.formatDateTime(entry.getKey())
                                + "]，单位换算前数值为null，不需要进行单位换算");

                        afterDatas.put(entry.getKey(), null);
                    } else {
                        if (entry.getValue().isNaN() == true) {
                            //原来的时间点值为null或NaN
                            logger.info("calcResultValueUnitConvert 计算结果数值单位换算，数据时间[" + LocalDateTimeUtil.formatDateTime(entry.getKey())
                                    + "]，单位换算前数值为NaN，不需要进行单位换算");

                            afterDatas.put(entry.getKey(), Double.NaN);
                        } else {
                            double value = entry.getValue().doubleValue();
                            //如果有单位换算系数，先乘以单位换算系数
                            if (Double.isNaN(modulus) == false)
                                value = value * modulus;

                            //如果有乘以时间长度，再乘以点号的时间长度
                            if (StringUtils.isNotBlank(tmtypeStr)) {
                                //需要根据点号的时段类型及当前数据时标的时间点计算出时间长度；如月点号的总天数可能是28、29、30、31天
                                //点号时段类型为旬、月、季度、年时需要根据当前数据时标计算天数；如果是周固定为7天；如果是天以下时段类型不需要乘以天数
                                if (tmseg == QmsPointTimeSegmentEnum.WEEK)
                                    value = value * 7.0f;
                                else if (tmseg.getIndex() >= QmsPointTimeSegmentEnum.TEN_DAYS.getIndex()) {
                                    int days = QmsTimeUtil.getSpanDays(entry.getKey(), tmseg);
                                    if (days > 0x0)
                                        value = value * days;
                                }
                                //乘以的时段长度是小时，需要再乘以24小时
                                //乘以的时段长度是分钟，需要再乘以24小时*60分钟
                                //乘以的时段长度是秒，需要再乘以24小时*60分钟*60秒
                                if (StringUtils.equalsIgnoreCase(tmtypeStr, "h"))
                                    value = value * 24.0f;
                                else if (StringUtils.equalsIgnoreCase(tmtypeStr, "m"))
                                    value = value * 24.0f * 60.0f;
                                else if (StringUtils.equalsIgnoreCase(tmtypeStr, "s"))
                                    value = value * 24.0f * 60.0f * 60.0f;
                            }

                            logger.info("calcResultValueUnitConvert 计算结果数值单位换算，数据时间[" + LocalDateTimeUtil.formatDateTime(entry.getKey())
                                    + "]，单位换算前数值[" + entry.getValue().doubleValue() + "]，单位换算后数值[" + value + "]");

                            afterDatas.put(entry.getKey(), value);
                        }
                    }
                }

                //替换计算结果
                this.result.setDatas(afterDatas);
            }
        } else {
            logger.info("calcResultValueUnitConvert 由于计算方法、计算目标或计算结果中的数据为空无法进行计算结果数值单位换算");
        }
    }

    @Override
    public void validInput() {

    }

    @Override
    public void calc() {

    }
}
